Managing Configuration Using Externalized Properties
Course: Advanced Java Training
Topic: Managing Configuration Using Externalized Properties in Spring Boot
Course Link: Advanced Java Training Course
Demo Link: Register for a Course Demo
JustAcademy Website: Visit JustAcademy
1. Introduction to Externalized Configuration
Externalized configuration is a software development practice in which application settings are maintained separately from the application's Java source code. In Spring Boot, externalized properties allow developers to configure application behavior without changing or recompiling business logic every time a setting changes.
Applications commonly require configuration values such as server ports, database URLs, logging levels, API endpoints, file paths, feature flags, and integration settings. Hardcoding these values in Java classes makes applications more difficult to maintain and deploy across different environments.
Spring Boot supports external configuration through properties files, YAML files, environment variables, Java system properties, command-line arguments, and other supported property sources.
Why Is Externalized Configuration Important?
- Environment flexibility: The same application artifact can run with different development, testing, and production settings.
- Maintainability: Configuration can be updated without modifying business logic.
- Deployment flexibility: Deployment tools can supply settings through environment variables or command-line arguments.
- Security: Sensitive values can be supplied through protected environment settings or secret-management systems rather than committed to source code.
- Consistency: Teams can establish standardized configuration conventions.
- Testing: Tests can use dedicated settings without changing production configuration.
2. Understanding Property Sources in Spring Boot
A property source is a location or mechanism from which Spring Boot obtains configuration values. When the application requests a property, Spring resolves it from the available configuration sources according to the framework's property-resolution rules and precedence.
Common Property Sources
| Property Source |
Description |
Example |
| application.properties |
Stores configuration as key-value pairs. |
server.port=8081 |
| application.yml |
Stores configuration in a hierarchical YAML structure. |
server: followed by an indented port value. |
| Environment variables |
Supplies values from the operating system or deployment environment. |
SERVER_PORT=9090 |
| Java system properties |
Supplies properties through JVM startup options. |
-Dserver.port=9090 |
| Command-line arguments |
Supplies configuration when launching the application. |
--server.port=9090 |
| External configuration files |
Stores settings outside the packaged application. |
An external application.properties file. |
| Profile-specific files |
Provides settings for a particular environment or profile. |
application-prod.properties |
| Custom property sources |
Allows applications to add supported configuration sources programmatically. |
A custom property source registered with Spring. |
The exact precedence depends on the property source and how the application is launched. For common Spring Boot configuration, command-line arguments generally override Java system properties, environment variables, and packaged configuration files.
3. Using application.properties
The application.properties file is a standard location for Spring Boot settings. It is commonly stored in src/main/resources.
Example Configuration
spring.application.name=employee-management
server.port=8081
app.company.name=ABC Technologies
app.company.location=Mumbai
logging.level.root=INFO
logging.level.com.example.employee=DEBUG
Explanation
spring.application.name defines the application name.
server.port configures the embedded web server's listening port.
app.company.name and app.company.location are custom application properties.
logging.level.root configures the root logging level.
logging.level.com.example.employee sets the logging level for the specified package.
Spring Boot recognizes its documented properties automatically. Custom properties must be read by the application, for example through @Value or @ConfigurationProperties.
4. Using application.yml
YAML provides a structured alternative to properties files. It represents related configuration values using nested keys and indentation.
Example Configuration
spring:
application:
name: employee-management
server:
port: 8081
app:
company:
name: ABC Technologies
location: Mumbai
logging:
level:
root: INFO
com.example.employee: DEBUG
In this example, the YAML keys represent the same configuration structure that can be expressed through dotted properties keys. Use consistent indentation with spaces and avoid duplicate keys at the same level.
Properties vs. YAML
| Feature |
Properties |
YAML |
| File extension |
.properties |
.yml or .yaml |
| Format |
Key-value pairs |
Hierarchical mappings and lists |
| Nested configuration |
Usually uses dotted names |
Uses indentation |
| Comments |
Use # |
Use # |
| Common issue |
Incorrect property names or values |
Incorrect indentation or invalid YAML syntax |
Both formats are supported by Spring Boot. Choose the format that best matches the team's conventions and the complexity of the configuration.
5. Accessing Externalized Properties in Java
Spring Boot provides several ways to access configuration values inside Java classes. The most commonly used approaches are @Value, Environment, and @ConfigurationProperties.
5.1 Using @Value
The @Value annotation injects an individual property into a Spring-managed component. It is suitable for small numbers of configuration values.
application.properties
app.company.name=ABC Technologies
app.company.location=Mumbai
CompanyInformation.java
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class CompanyInformation {
@Value("${app.company.name}")
private String companyName;
@Value("${app.company.location}")
private String location;
public void displayInformation() {
System.out.println("Company: " + companyName);
System.out.println("Location: " + location);
}
}
Explanation:
@Component registers the class as a Spring-managed bean.
@Value("${app.company.name}") retrieves the company name from the available property sources.
@Value("${app.company.location}") retrieves the location.
- Spring injects the resolved values when creating the bean.
You can provide a default value if a property is not defined:
@Value("${app.company.name:Default Company}")
private String companyName;
5.2 Using the Environment Interface
Spring's Environment abstraction allows a component to retrieve configuration values dynamically by property name. It is useful when a class needs to inspect multiple properties or query the active environment.
package com.example.demo;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class ApplicationSettings {
private final Environment environment;
public ApplicationSettings(Environment environment) {
this.environment = environment;
}
public void printSettings() {
String appName = environment.getProperty(
"spring.application.name", "demo-application"
);
String port = environment.getProperty(
"server.port", "8080"
);
System.out.println("Application: " + appName);
System.out.println("Configured port: " + port);
}
}
The getProperty() method can return a default value when the requested property is unavailable. Use this approach when direct access to the environment is useful, rather than as a replacement for structured configuration in every class.
5.3 Using @ConfigurationProperties
For multiple related settings, @ConfigurationProperties is generally preferable because it groups configuration into a structured Java object and supports type conversion and validation.
application.properties
app.company.name=ABC Technologies
app.company.location=Mumbai
app.company.employee-count=150
CompanyProperties.java
package com.example.demo.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "app.company")
public class CompanyProperties {
private String name;
private String location;
private int employeeCount;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public int getEmployeeCount() {
return employeeCount;
}
public void setEmployeeCount(int employeeCount) {
this.employeeCount = employeeCount;
}
}
Register the properties class by adding @ConfigurationPropertiesScan to the main application class, or by using @EnableConfigurationProperties(CompanyProperties.class) in a configuration class.
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Inject the configuration object into a service or controller using constructor injection. The properties class can then be used wherever those settings are needed.
Comparison of Configuration Access Methods
| Method |
Best Use Case |
Main Advantage |
@Value |
A small number of individual settings. |
Simple property injection. |
Environment |
Programmatic property lookup. |
Can query property values by name. |
@ConfigurationProperties |
Groups of related settings. |
Structured, type-safe configuration binding and support for validation. |
6. Understanding Configuration Precedence
Spring Boot can read a property from several sources. If the same property is defined in multiple places, Spring Boot resolves it according to the precedence rules of those sources.
For example, suppose the packaged configuration contains:
server.port=8080
You can override that value when starting the application:
java -jar target/demo.jar --server.port=9090
The command-line argument normally takes precedence over the packaged file, so the application attempts to use port 9090.
Common Configuration Sources
- Configuration files packaged inside the application.
- Profile-specific configuration files.
- External configuration files.
- Operating-system environment variables.
- Java system properties.
- Command-line arguments.
- Test-specific property sources when running tests.
The complete precedence order is more detailed than this list and includes additional sources. When diagnosing a value that does not match the file, consult the official Spring Boot Externalized Configuration documentation.
7. Managing External Configuration Files
By default, Spring Boot searches for application configuration in recognized classpath and filesystem locations. Keeping configuration outside the packaged JAR can allow deployment settings to change without rebuilding the application.
Example Project Structure
employee-management/
├── src/
│ └── main/
│ ├── java/
│ └── resources/
│ └── application.properties
├── config/
│ └── application.properties
├── pom.xml
└── target/
└── employee-management.jar
For a deployed application, the external config/application.properties file may override corresponding values from the packaged configuration when it is found in a recognized location.
Using an Additional Configuration Location
The spring.config.additional-location setting adds configuration locations while retaining the default search locations.
java -jar employee-management.jar \
--spring.config.additional-location=optional:file:./config/
The example uses a Unix-style line continuation. On Windows Command Prompt, enter the command on one line or use the appropriate continuation syntax for the shell.
The optional: prefix allows startup to continue if the specified location does not exist. Without it, a missing required configuration location can prevent startup.
Difference Between Location and Additional Location
| Property |
Purpose |
spring.config.location |
Specifies configuration locations and replaces the default search locations. |
spring.config.additional-location |
Adds configuration locations to the default search locations. |
spring.config.name |
Changes the basename Spring Boot uses when searching for configuration files. |
spring.config.import |
Imports additional configuration data from supported locations. |
These settings are processed early during application startup. Supply them through an appropriate environment variable, JVM system property, or command-line argument.
8. Using Spring Profiles for Environment-Specific Configuration
Profiles allow an application to use different configuration settings for different environments. A typical application might have development, testing, staging, and production environments.
Example File Structure
src/main/resources/
├── application.properties
├── application-dev.properties
├── application-test.properties
└── application-prod.properties
Development Configuration
# application-dev.properties
server.port=8081
logging.level.root=DEBUG
Production Configuration
# application-prod.properties
server.port=8080
logging.level.root=WARN
Activate a Profile
You can activate a profile with a command-line argument:
java -jar target/employee-management.jar \
--spring.profiles.active=dev
You can also set the environment variable SPRING_PROFILES_ACTIVE to dev. Spring Boot then loads the configuration associated with that active profile along with the applicable default configuration.
Use profiles to manage legitimate differences between environments. Do not use them as a substitute for securely storing passwords, API keys, or other sensitive information.
9. Managing Sensitive Properties and Secrets
Externalized configuration helps separate secrets from application code. However, storing a password in an external file does not automatically make it secure. Access to the file, deployment environment, and secret storage system must also be controlled.
Example: Database Configuration
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
These placeholders refer to environment variables or other supported property sources. Ensure the variables are provided in the deployment environment and that the required database driver and data-access dependencies are present.
Security Best Practices
- Never commit real production credentials to source control.
- Use protected environment variables or a dedicated secrets-management service.
- Restrict access to configuration files and deployment systems.
- Use separate credentials for development, testing, and production.
- Rotate credentials when required by security policy.
- Avoid printing secrets in application logs or exception messages.
- Do not assume that a property is secure simply because it is stored outside the Java source code.
10. Testing Externalized Configuration
Configuration should be tested to confirm that the application behaves correctly with the expected values. Spring Boot testing facilities allow tests to override configuration without changing the production configuration file.
Example Using @SpringBootTest
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SpringBootTest(properties = {
"app.company.name=Test Company"
})
class ConfigurationTest {
@Value("${app.company.name}")
private String companyName;
@Test
void shouldLoadTestConfiguration() {
assertEquals("Test Company", companyName);
}
}
This test supplies a test-specific value and verifies that it can be injected into the Spring test context. The actual test class should be placed in the appropriate test source directory, and the project must include the relevant Spring Boot testing dependencies.
What Should Be Tested?
- Required properties are present.
- Configuration values bind to the expected Java types.
- Profile-specific settings are applied correctly.
- Invalid configuration is detected early where validation is configured.
- Tests can override properties without modifying production configuration.
- Secrets are not exposed in logs, test reports, or source control.
11. Troubleshooting Externalized Properties
| Problem |
Possible Cause |
Solution |
| Property is not found |
Incorrect key, wrong file location, or missing configuration source. |
Check the key name and ensure the file is in a recognized location. |
| Unexpected property value |
A higher-priority property source overrides the file value. |
Inspect command-line arguments, system properties, environment variables, active profiles, and external files. |
| Profile settings are ignored |
The intended profile is not active or the filename is incorrect. |
Verify spring.profiles.active and the profile-specific filename. |
| Application fails due to a missing placeholder |
A required value was not supplied. |
Define the property or provide a suitable default if appropriate. |
| Configuration properties are not bound |
The properties class is not registered or the prefix does not match. |
Check the annotation, prefix, field names, and configuration-properties registration. |
| External file is not loaded |
The file is outside the configured search locations. |
Use a recognized location or configure spring.config.additional-location. |
| Application fails validation |
A configured value violates a declared constraint. |
Review the validation message and correct the supplied value. |
| Secret appears in logs |
Configuration values are being logged directly. |
Remove sensitive logging and review log access and retention policies. |
12. Practical Project: Externalized Configuration for an Employee API
Objective: Create a Spring Boot application that reads configuration from external properties and supports environment-specific settings.
Step 1: Generate the Project
Open Spring Initializr, select Maven and Java, choose a compatible Spring Boot version, and add Spring Web.
Step 2: Configure application.properties
spring.application.name=employee-management
server.port=8082
app.company.name=ABC Technologies
app.company.location=Mumbai
Step 3: Create a Controller
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CompanyController {
@Value("${app.company.name}")
private String companyName;
@Value("${app.company.location}")
private String location;
@GetMapping("/company")
public String getCompany() {
return companyName + " is located in " + location;
}
}
Step 4: Run the Application
# Windows
mvnw.cmd spring-boot:run
# macOS or Linux
./mvnw spring-boot:run
Step 5: Test the Endpoint
Open the following URL in a browser or API client:
http://localhost:8082/company
Expected response:
ABC Technologies is located in Mumbai
Step 6: Override a Property
Start the application with an overridden company name:
java -jar target/employee-management.jar \
--app.company.name="Demo Technologies"
Use the actual generated JAR filename. The endpoint should reflect the supplied value when the application is launched with the override.
Step 7: Add Environment-Specific Settings
Create an application-dev.properties file, activate the dev profile, and verify that the development configuration is applied. Document the configuration sources used in the project.
13. Best Practices for Managing Externalized Properties
- Use clear, consistent property names, preferably in lowercase kebab-case for custom configuration.
- Use
@ConfigurationProperties for related configuration values.
- Use
@Value for simple, isolated property injections.
- Use profiles for environment-specific settings.
- Understand property precedence before troubleshooting unexpected values.
- Keep sensitive values in appropriately protected secret stores or deployment settings.
- Validate required settings during application startup when practical.
- Keep default configuration safe and suitable for local development.
- Document external configuration requirements for deployment teams.
- Test configuration behavior across supported environments.
- Follow a consistent strategy for Properties and YAML files.
- Consult the official Spring Boot documentation when using version-specific configuration features.
14. Interview Questions and Answers
Q1. What is externalized configuration?
Answer: It is the practice of maintaining application settings separately from application code so the same application can run with different settings in different environments.
Q2. Which configuration formats does Spring Boot support?
Answer: Spring Boot supports Java Properties files and YAML files, along with environment variables, system properties, command-line arguments, and other supported property sources.
Q3. What is the purpose of @Value?
Answer: It injects an individual configuration value into a Spring-managed bean using a property placeholder.
Q4. What is the advantage of @ConfigurationProperties?
Answer: It binds related properties into a structured Java object, supports type conversion, and can be combined with validation.
Q5. What are Spring profiles?
Answer: Profiles allow an application to activate environment-specific configuration and beans, such as settings for development or production.
Q6. How can you override a property at startup?
Answer: A property can be overridden using supported higher-priority sources, such as command-line arguments, environment variables, or Java system properties.
Q7. What is the difference between spring.config.location and spring.config.additional-location?
Answer: spring.config.location replaces the default configuration search locations, while spring.config.additional-location adds locations to the defaults.
Q8. Why should secrets be externalized?
Answer: Externalizing secrets reduces the risk of exposing credentials in source code, but the external storage and access permissions must still be secured.
Q9. How can configuration be tested?
Answer: Tests can supply dedicated property values through Spring Boot test annotations and verify that the application binds and uses those values correctly.
Q10. What should you do if a property has an unexpected value?
Answer: Inspect the active profiles and all relevant property sources, including external files, environment variables, system properties, and command-line arguments.
15. Quick Revision Checklist
- Understand externalized configuration and its benefits.
- Know the difference between Properties and YAML files.
- Understand property sources and configuration precedence.
- Know how to use
@Value, Environment, and @ConfigurationProperties.
- Understand how to activate Spring profiles.
- Know how to load external configuration files.
- Keep secrets outside source control and protect their storage.
- Test configuration values and troubleshoot unexpected overrides.
16. Conclusion
Externalized properties are an essential part of building maintainable Spring Boot applications. They allow developers to separate settings from business logic, configure different environments, override values at deployment time, and organize configuration into structured Java objects.
By understanding property sources, precedence, profiles, external files, secret management, and configuration testing, developers can build applications that are easier to deploy, troubleshoot, and maintain.
Useful Learning Resources